package main
import(
	"fmt"
	_ "github.com/go-sql-driver/mysql-master"
	"database/sql"
)
// mysql 预处理 (例如:一条删除sql的语句中，可以分为命令部分与占位符部分，预处理的含义就是客户端每次只传递占位符部分就行，命令行部分由mysql服务端执行)
// 普通sql语句执行过程: 
// 1.客户端对sql语句进行占位符替换得到完整的sql语句
// 2。客户端发送完整sql语句到mysql服务端
// 3.mysql服务端执行完整的sql语句并将结果返回给客户端

// 预处理执行过程
// 1.把sql语句分为两部分，命令部分与数据部分
// 2.先把命令部分发送给mysql服务端，mysql服务端进行sql预处理
// 3,然后把数据部分发送给mysql服务端,mysql服务端对sql语句进行占位符的替换
// 4.mysql服务端执行完整的sql语句并将结果返回给客户端

// 预处理的作用: 1.优化mysql重复执行sql方法,提升服务性能  2.避免sql诸如问题

type table struct{
	id int
	name string
	age int
}
var db *sql.DB
func initDB()(err error){
	// 1.输入数据库的连接信息
	dsn:="root:123@tcp(127.0.0.1:3306)/sql_test"
	// 2.连接数据库
	db,err=sql.Open("mysql",dsn)
	if err!=nil{
		return
	}
	// 3.检查数据库最终是否连接成功
	err=db.Ping()
	if err!=nil{
		return
	}
	// 设置数据库连接池的最大连接数
	db.SetMaxOpenConns(100)
	// 设置最大空闲连接数
	db.SetMaxIdleConns(10)
	return
}

// 预审mysql之查询sql语句
func pre_query(){
	// 1.需要查询的sql语句
	sqlStr:=`select id,name,age from user where id >?;`
	// 2.发送sql至服务端
	stmt,err:=db.Prepare(sqlStr)
	if err!=nil{
		fmt.Printf("prepare sql failed,err:%v\n",err)
		return
	}
	defer stmt.Close()
	rows, err := stmt.Query(0)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
		return
	}
	defer rows.Close()
	// 循环读取结果集中的数据
	for rows.Next() {
		var u table
		err := rows.Scan(&u.id, &u.name, &u.age)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
	}
}
// 插入数据 （插入、删除、更新都是采用Exec()方法）
func insertsql(){
	// 1.写要插入的sql语句(以占位符的方法)
	sqlStr:=`insert into user(name,age)values(?,?);`
	// 2.发送sql 至服务端
	stmt,err:=db.Prepare(sqlStr)
	if err!=nil{
		fmt.Printf("prepare sql failed,err:%v\n",err)
		return
	}
	defer stmt.Close()
	// 后续只需要拿stmt去执行操作即可
	var m =map[string]int{
		"小三":19,
		"二奶":24,
		"白洁":33,
	}
	for k,v:=range m{
	// 3.执行要插入的sql语句
		stmt.Exec(k,v)
	}
}
func main(){
	err:=initDB()
	if err!=nil{
		fmt.Printf("mysql connected failed,err:%v\n",err)
		return
	}
	pre_query()
	insertsql()
}